package com.birdboot.core;

import com.birdboot.annotations.Controller;
import com.birdboot.annotations.RequestMapping;
import com.birdboot.controller.UserController;
import com.birdboot.http.HttpServletRequest;
import com.birdboot.http.HttpServletResponse;

import javax.activation.MimetypesFileTypeMap;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URISyntaxException;
/**
 * V8新增能容:
 * DispatcherServlet是由SpringMVC框架提供的一个Servlet类,用于与Tomcat整合使用的类.
 * 具体作用是接收处理请求的工作
 *
 * 这里我们先将原ClientHandler中处理请求的所有工作移动到这个类的service方法上
 * 注:
 * Tomcat中处理请求的类都需要继承HttpServlet,而实现类都需要重写方法:service,用于处理请求
 * SpringMVC提供的DispatcherServlet实际上也这样做了.我们这里不需要真的去继承了,但是格式上
 * 与其保持一致.
 */
public class DispatcherServlet {

    private static DispatcherServlet instance = new DispatcherServlet();

    private static File baseDir;
    private static File staticDir;
    static{
        try {
            baseDir = new File(
                    DispatcherServlet.class.getClassLoader()
                            .getResource(".").toURI()
            );
            staticDir = new File(baseDir,"static");
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    private DispatcherServlet(){}

    public static DispatcherServlet getInstance(){
        return instance;
    }

    public void service(HttpServletRequest request, HttpServletResponse response) {
        String path = request.getRequestURI();
        //System.out.println("抽象路径："+path);
        if("/".equals(path)){
            path = "/index.html";
        }

        //判断本次请求是否为请求业务
        /*
            path: /regUser
            当我们得到本次请求路径path的值后，我们首先要查看是否为请求业务:
            1:扫描controller包下的所有类
            2:查看哪些被注解@Controller标注的过的类(只有被该注解标注的类才认可为业务处理类)
            3:遍历这些类，并获取他们的所有方法，并查看哪些时业务方法
              只有被注解@RequestMapping标注的方法才是业务方法
            4:遍历业务方法时比对该方法上@RequestMapping中传递的参数值是否与本次请求
              路径path值一致?如果一致则说明本次请求就应当由该方法进行处理
              因此利用反射机制调用该方法进行处理。 提示:反射调用后要记得return,避免执行后续处理静态资源的操作
            5:如果扫描了所有的Controller中所有的业务方法，均未找到与本次请求匹配的路径
              则说明本次请求并非处理业务，那么执行下面请求静态资源的操作
         */
        try {
            File dir = new File(baseDir,"com/birdboot/controller");
            //1获取该目录下的所有.class文件
            File[] files = dir.listFiles(f->f.getName().endsWith(".class"));
            for(File f : files){
                //根据class文件的文件名来确定类名
                String fileName = f.getName();
                String className = fileName.substring(0,fileName.indexOf("."));
                //加载类对象
                Class cls = Class.forName("com.birdboot.controller."+className);
                //判断该类是否被注解@Controller标注
                if(cls.isAnnotationPresent(Controller.class)){
                    //Object obj = cls.newInstance();
                    //扫描里面所有的方法，并查看有注解@RequestMapping的方法
                    Method[] methods = cls.getDeclaredMethods();
                    for(Method m : methods){
                        //判断该方法是否被注解@RequestMapping标注
                        //通过@RequestMapping注解获取上面的参数(该方法处理的请求路径)
                        //判断本次请求路径是否与该参数值一致，如果是则说明本次请求应当由该方法处理
                        if(m.isAnnotationPresent(RequestMapping.class)
                                && m.getAnnotation(RequestMapping.class).value().equals(path)){
                            //实例化这个Controller
                            Object obj = cls.newInstance();//每次只执行一个方法，在执行前再new实例就可以
                            //调用该方法处理本次请求
                            m.invoke(obj,request,response);
                            //处理完毕后return,避免执行下面处理静态资源的逻辑
                            return;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        File file = new File(staticDir,path);
        if(file.isFile()){
            response.setContentFile(file);
            response.addHeader("Server","BirdServer");
        }else{
            //重定向404页面
            file = new File(staticDir,"404.html");
            response.setContentFile(file);

            response.setStatusCode(404);
            response.setStatusReason("NotFound");
            response.addHeader("Server","BirdServer");
        }


    }
}
